﻿#include "GeomtryActorGenerator.h"
#include <QDebug>
#include <QCoreApplication>
#include <STEPControl_Reader.hxx>
#include <Standard_Integer.hxx>
#include <TopoDS_Shape.hxx>
#include <IFSelect_PrintCount.hxx>
#include <IFSelect_ReturnStatus.hxx>
#include <IVtkOCC_ShapeMesher.hxx>
#include <IVtkTools_DisplayModeFilter.hxx>
#include <IVtkTools_ShapeDataSource.hxx>
#include <IVtkVTK_ShapeData.hxx>
#include <IGESControl_Reader.hxx>

#include <vtkPolyDataNormals.h>
#include <vtkClipPolyData.h>
#include <vtkDataSetMapper.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkLookupTable.h>
#include <vtkDataSet.h>
#include <vtkActor.h>
#include <vtkPlane.h>
#include <vtkPolyData.h>
#include <vtkProperty.h>
#include <vtkAppendPolyData.h>
#include <QFileInfo>
#include <vtkSTLReader.h>
#include "BaseModule/IBaseSignal.h"

namespace pst
{
    GeomtryActorGenerator::GeomtryActorGenerator(QObject* parent)
        : QObject(parent)
        , m_fileName()
        , m_isActiveClip(false)
        , m_clipPlaneNormalDirection{ 1.0, 0.0, 0.0 }
        , m_clipPlaneOrigin{ 0.0, 0.0, 0.0 }
        , m_isGeometryRead(false)
        //, m_dataSet(nullptr)
        , m_errorMessage()
        , m_clipPlane(vtkSmartPointer<vtkPlane>::New())
        , m_clipFilter(vtkSmartPointer<vtkClipPolyData>::New())
        , m_mapper(vtkSmartPointer<vtkPolyDataMapper>::New())
        , m_actor(vtkSmartPointer<vtkActor>::New())
        , m_appendPolyData(vtkSmartPointer<vtkAppendPolyData>::New())
    {
        m_mapper->SetInterpolateScalarsBeforeMapping(true);
        //m_mapper->SetColorModeToMapScalars();
        m_mapper->ScalarVisibilityOff();
        m_actor->SetPickable(false);
        //m_mapper->SetUseLookupTableScalarRange(1);
    }

    GeomtryActorGenerator::~GeomtryActorGenerator()
    {
    }

    void GeomtryActorGenerator::setFileNameList(const QStringList& fileName)
    {
        m_fileName = fileName;
    }

    QStringList GeomtryActorGenerator::getFileNameList() const
    {
        return m_fileName;
    }

    void GeomtryActorGenerator::setIsActiveClip(bool isActiveClip)
    {
        m_isActiveClip = isActiveClip;
    }

    bool GeomtryActorGenerator::getIsActiveClip() const
    {
        return m_isActiveClip;
    }

    void GeomtryActorGenerator::setClipPlaneNormalDirection(double normalDirection[3])
    {
        m_clipPlaneNormalDirection[0] = normalDirection[0];
        m_clipPlaneNormalDirection[1] = normalDirection[1];
        m_clipPlaneNormalDirection[2] = normalDirection[2];
    }

    double* GeomtryActorGenerator::getClipPlaneNormalDirection()
    {
        return m_clipPlaneNormalDirection;
    }

    void GeomtryActorGenerator::setClipPlaneOrigin(double origin[3])
    {
        m_clipPlaneOrigin[0] = origin[0];
        m_clipPlaneOrigin[1] = origin[1];
        m_clipPlaneOrigin[2] = origin[2];
    }

    double* GeomtryActorGenerator::getClipPlaneOrigin()
    {
        return m_clipPlaneOrigin;
    }

    int GeomtryActorGenerator::updateActor()
    {
        if (m_fileName.isEmpty())
        {
            m_errorMessage = QStringLiteral("没有几何文件");
            return 2;// 没有几何文件
        }

        int returnStatus = 0;
        if (!m_isGeometryRead)
        {
            returnStatus = readGeometryFromFile();
            returnStatus = readGeometryFromFile();
            m_isGeometryRead = true;
        }

        vtkNew<vtkPolyDataNormals> normals;
        if (m_isActiveClip)
        {

            m_clipFilter->SetInputConnection(m_appendPolyData->GetOutputPort());
            m_clipFilter->SetClipFunction(m_clipPlane);
            // 设置 InsideOut 为 false，表示保留平面正法线方向一侧的数据
            m_clipFilter->SetInsideOut(false);
            m_clipPlane->SetNormal(m_clipPlaneNormalDirection);
            //m_mapper->SetLookupTable(m_lookupTable);
            m_clipPlane->SetOrigin(m_clipPlaneOrigin);
            m_clipFilter->Update();

            normals->SetInputConnection(m_clipFilter->GetOutputPort());
        }
        else
        {
            normals->SetInputConnection(m_appendPolyData->GetOutputPort());
        }
        normals->ComputePointNormalsOn();
        normals->FlipNormalsOn();
        normals->Update();

        m_geometryPolyData = normals->GetOutput();
        m_mapper->SetInputConnection(normals->GetOutputPort());
        m_actor->SetMapper(m_mapper);
        return returnStatus;
    }

    vtkSmartPointer<vtkPolyData> GeomtryActorGenerator::getGeometryPolyData()
    {
        return m_geometryPolyData;
    }

    vtkSmartPointer<vtkActor> GeomtryActorGenerator::getActor()
    {
        return m_actor;
    }

    QString GeomtryActorGenerator::getErrorMessage() const
    {
        return m_errorMessage;
    }

    int GeomtryActorGenerator::readGeometryFromFile()
    {
        m_errorMessage.clear();
        int failCount = 0;
        TopoDS_Shape aShape;
        //emit IBaseSignalInstance->signal_UpdateStatusBarInformation(QStringLiteral("显示模型正在进行中..."), true);
        QCoreApplication::processEvents();
        for (const auto& file : m_fileName)
        {        
            QFileInfo fileInfo(file);
            auto suffix = fileInfo.suffix();

            if (suffix.toUpper() == "IGS" || suffix.toUpper() == "IGES")
            {
                IGESControl_Reader igesReader;
                IFSelect_ReturnStatus status = igesReader.ReadFile((Standard_CString)file.toUtf8());
                if (status != IFSelect_RetDone)
                {
                    qDebug() << "读取 IGES 文件失败！" << file;
                    m_errorMessage += QStringLiteral("读取几何文件失败: ") + file + "\n";
                    failCount++;
                    continue;
                }
                igesReader.TransferRoots();
                aShape = igesReader.OneShape();


                // 必须有编号 否则拾取时无法被区分 m_picker->GetPickedActors();会拾取到所有的actor
                // static Standard_Integer ShapeID = 0; ++ShapeID;
                Handle(IVtkOCC_Shape) aShapeWrapper = new IVtkOCC_Shape(aShape);
                // aShapeWrapper->SetId(ShapeID);

                /// 高集成方案
                vtkNew<IVtkTools_ShapeDataSource> occSource;
                occSource->SetShape(aShapeWrapper);

                ////        //celan
                // vtkNew<vtkCleanPolyData> cleaner;
                // cleaner->SetInputConnection(occSource->GetOutputPort());
                // cleaner->Update();

                vtkNew<IVtkTools_DisplayModeFilter> DMfilter; // 显示模式
                DMfilter->AddInputConnection(occSource->GetOutputPort());
                DMfilter->SetDisplayMode(DM_Shading);
                DMfilter->SetFaceBoundaryDraw(true);
                DMfilter->SetSmoothShading(true);

                vtkNew<vtkDataSetSurfaceFilter> surfaceFilter;
                surfaceFilter->SetInputConnection(DMfilter->GetOutputPort());
                surfaceFilter->Update();

                m_appendPolyData->AddInputConnection(surfaceFilter->GetOutputPort());
                m_appendPolyData->Update();
            }
            else if (suffix.toUpper() == "STP" || suffix.toUpper() == "STEP")
            {
                STEPControl_Reader stpReader;
                if (stpReader.ReadFile((Standard_CString)file.toUtf8()) != IFSelect_RetDone)
                {
                    qDebug() << "Cannot open STEP file: " << file;
                    m_errorMessage += QStringLiteral("读取几何文件失败: ") + file + "\n";
                    failCount++;
                    continue;
                }
                stpReader.TransferRoots();
                aShape = stpReader.OneShape();


                // 必须有编号 否则拾取时无法被区分 m_picker->GetPickedActors();会拾取到所有的actor
                // static Standard_Integer ShapeID = 0; ++ShapeID;
                Handle(IVtkOCC_Shape) aShapeWrapper = new IVtkOCC_Shape(aShape);
                // aShapeWrapper->SetId(ShapeID);

                /// 高集成方案
                vtkNew<IVtkTools_ShapeDataSource> occSource;
                occSource->SetShape(aShapeWrapper);

                ////        //celan
                // vtkNew<vtkCleanPolyData> cleaner;
                // cleaner->SetInputConnection(occSource->GetOutputPort());
                // cleaner->Update();

                vtkNew<IVtkTools_DisplayModeFilter> DMfilter; // 显示模式
                DMfilter->AddInputConnection(occSource->GetOutputPort());
                DMfilter->SetDisplayMode(DM_Shading);
                DMfilter->SetFaceBoundaryDraw(true);
                DMfilter->SetSmoothShading(true);

                vtkNew<vtkDataSetSurfaceFilter> surfaceFilter;
                surfaceFilter->SetInputConnection(DMfilter->GetOutputPort());
                surfaceFilter->Update();

                m_appendPolyData->AddInputConnection(surfaceFilter->GetOutputPort());
                m_appendPolyData->Update();
            }
            else if (suffix.toUpper() == "STL")
            {
                vtkSmartPointer<vtkSTLReader> stlReader = vtkSmartPointer<vtkSTLReader>::New();
                stlReader->SetFileName(file.toUtf8().constData());
                stlReader->Update();

                // 获取输出数据
                vtkSmartPointer<vtkPolyData> polyData = stlReader->GetOutput();

                // 如果没有读取到有效数据，则提示错误
                if (polyData->GetNumberOfPoints() == 0)
                {
                    qDebug() << "Cannot open STL file: " << file;
                    m_errorMessage += QStringLiteral("读取几何文件失败: ") + file + "\n";
                    failCount++;
                    continue;
                }

                m_appendPolyData->AddInputConnection(stlReader->GetOutputPort());
                m_appendPolyData->Update();
            }
            else
            {
                qDebug() << "Cannot open file: " << file;
                m_errorMessage += QStringLiteral("读取几何文件失败: ") + file + "\n";
                failCount++;
                continue;
            }
        }

        if (failCount == 0)
        {
            //emit IBaseSignalInstance->signal_UpdateStatusBarInformation(QStringLiteral("显示模型完成！"),false);
            return 0; //全部成功
        }
        if (failCount == m_fileName.size())
        {
            //emit IBaseSignalInstance->signal_UpdateStatusBarInformation(QStringLiteral("显示模型失败！"),false);
            return 2;//全部失败
        }
        return 1;//部分失败
    }
}
